﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Daybreak.Core.Network.Tcp
{
    public class TcpNetServer : NetBase
    {
        #region Variables

        private NetBase _this;

        private Socket server;

        private ManualResetEvent allDone = new ManualResetEvent(true);

        private int count_connection_id = 0;

        internal Dictionary<int, TcpNetServerConnection> connections;

        public event Error OnError;

        #endregion

        #region Methods

        public TcpNetServer(string assemblyFile)
            : base(assemblyFile)
        {
            _this = this;

            this.CreatePacketConfig();

            connections = new Dictionary<int, TcpNetServerConnection>();
        }

        public void Start(string host, int port)
        {
            try
            {
                IPEndPoint iep = new IPEndPoint(Dns.GetHostEntry(host).AddressList[0], port);
                EndPoint ep = (EndPoint)iep;

                server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                server.Bind(ep);
                server.Listen(1000);

                Thread acceptThread = new Thread(new ThreadStart(ThreadAccept), 262144);
                acceptThread.IsBackground = true;
                acceptThread.Start();

            }
            catch (SocketException ex)
            {
                NetError(ex.Message);
            }
        }

        private void ThreadAccept()
        {
            while (true)
            {
                try
                {
                    allDone.Reset();

                    server.BeginAccept(new AsyncCallback(AsyncEndAccept), server);

                    allDone.WaitOne();
                }
                catch (SocketException ex)
                {
                    NetError(ex.Message);
                }
            }
        }

        private void AsyncEndAccept(IAsyncResult ar)
        {
            try
            {
                Socket socket = (Socket)ar.AsyncState;

                allDone.Set();

                Socket acceptedSoc = socket.EndAccept(ar);

                count_connection_id++;

                Thread acceptThread = new Thread(new ThreadStart(ThreadAccept), 262144);
                acceptThread.IsBackground = true;
                acceptThread.Start();
            }
            catch (SocketException ex)
            {
                NetError(ex.Message);
            }
        }

        #endregion

    }

    public class TcpNetServerConnection
    {
        #region Variables

        private TcpNetServer serverObject;

        private DateTime lastTimePackage = DateTime.Now;

        private int connectionId;

        private Socket socket;

        private Thread thread;

        private int pendingPackeTime;

        #endregion


        #region Methods

        public TcpNetServerConnection(ref TcpNetServer obj)
        {
            serverObject = obj;
        }

        public void StartSend()
        {
            while (true)
            {
                try
                {
                     
                }
                catch (SocketException ex)
                {
                    serverObject.NetError(ex.Message);
                }
            }
        }

        public void StartReceive()
        {
            while (true)
            {
                try
                {
                    TimeSpan ts = new TimeSpan(DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond);
                    double totalSecondsNow = ts.TotalSeconds;
                    double totalSecodnsPackage = ((TimeSpan)(DateTime.Now - lastTimePackage)).TotalSeconds;
                    double result = totalSecondsNow - (totalSecondsNow - totalSecodnsPackage);

                    if (result >= pendingPackeTime)
                    {
                        serverObject.connections.Remove(connectionId);

                        socket.Shutdown(SocketShutdown.Both);
                        socket.Close();

                        thread.Abort();
                    }

                    byte[] buffer = new byte[1048576];

                    int rb = socket.Receive(buffer, 0, 1048576, SocketFlags.None);

                    if (rb > 0)
                    {
                        lastTimePackage = DateTime.Now;
                    }

                    Thread.Sleep(5);
                }
                catch (SocketException ex)
                {
                    serverObject.NetError(ex.Message);
                }
            }
        }

        #endregion

        #region Properties

        public int ID
        {
            get
            {
                return connectionId;
            }
            set
            {
                connectionId = value;
            }
        }

        public Socket Socket
        {
            set
            {
                socket = value;
            }
        }

        public Thread Thread
        {
            set
            {
                thread = value;
            }
        }

        public int PendingPackeTime
        {
            set
            {
                pendingPackeTime = value;
            }
        }

        #endregion
    }
}
